package tools.code.generator.utils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import tools.code.generator.service.FieldInfo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 根据模型文件生成对应的代码
 *
 * @author 沈东生
 */
public class ModelCodeGeneratorUtils {

    public static void generateParquetConvert(File outFile, List<FieldInfo> fieldInfos) throws IOException {
        List<String> lines = FileUtils.readLines(outFile, "utf-8");
        StringBuilder sb = new StringBuilder();
        boolean inSchema = false;
        boolean addSchema = false;
        boolean inRow = false;
        boolean addRow = false;
        boolean inDeserialization = false;
        boolean addDeserialization = false;
        for (String line : lines) {
            if (StringUtils.contains(line, "/*--end_schema*/")) {
                inSchema = false;

            }
            if (StringUtils.contains(line, "/*--end_row*/")) {
                inRow = false;

            }
            if (StringUtils.contains(line, "/*--end_deserialization*/")) {
                inDeserialization = false;

            }
            if (inSchema) {
                if (!addSchema) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);

                        sb.append(String.format("        list.add(new StructField(\"%s\", DataTypes.%sType, true, Metadata.empty()));", m.getHiveName(), m.getParquetType()));
                        sb.append("\n");
                    }
                    addSchema = true;
                }

            }
            if (inRow) {
                if (!addRow) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);
                        String toValue;
                        if (m.isConvertToJsonStr()) {
                            toValue = String.format("toJsonStr(m.%s())", m.getGetMethodName());
                        } else {
                            toValue = String.format("m.%s()", m.getGetMethodName());
                        }
                        sb.append(String.format("        list.add(%s);", toValue));
                        sb.append("\n");
                    }

                    addRow = true;
                }
            }
            if (inDeserialization) {
                if (!addDeserialization) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);
                        if (m.isConvertToJsonStr()) {
                            sb.append(String.format("        //ignore set %s ", m.getSetMethodName()));

                        } else {
                            sb.append(String.format("        m.%s(get%s(row,\"%s\"));", m.getSetMethodName(),StringUtils.capitalize(m.getParquetType()),m.getHiveName()));
                        }

                        sb.append("\n");
                    }
                    addDeserialization = true;
                }

            }
            if (!inSchema && !inRow && !inDeserialization) {
                sb.append(line).append("\n");
            }
            if (StringUtils.contains(line, "/*--start_schema*/")) {
                inSchema = true;
            }
            if (StringUtils.contains(line, "/*--start_row*/")) {
                inRow = true;
            }
            if (StringUtils.contains(line, "/*--start_deserialization*/")) {
                inDeserialization = true;
            }


        }
        FileUtils.write(outFile, sb.toString(), "UTF-8");
        System.out.println(sb);
    }

    public static void outDocFile(File outFile, List<FieldInfo> fieldInfos) throws IOException, ParseException, IllegalAccessException {
        FileOutputStream out = new FileOutputStream(outFile);
        ExcelUtils.createTheExcel(out, FieldInfo.class, fieldInfos);
        out.close();
    }

    public static void generateMongoConvert(File outFile, List<FieldInfo> fieldInfos) throws IOException {
        List<String> lines = FileUtils.readLines(outFile, "utf-8");
        StringBuilder sb = new StringBuilder();
        boolean inSchema = false;
        boolean addSchema = false;
        boolean inRow = false;
        boolean addRow = false;
        for (String line : lines) {
            if (StringUtils.contains(line, "/*--end_schema*/")) {
                inSchema = false;

            }
            if (StringUtils.contains(line, "/*--end_row*/")) {
                inRow = false;

            }
            if (inSchema) {
                if (!addSchema) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);
                        String toValue;
                        if (!m.isConvertToJsonStr()) {
                            toValue = String.format("m.%s()", m.getGetMethodName());
                            sb.append(String.format("        if(m.%s()!=null){ doc.put(\"%s\",%s);}", m.getGetMethodName(), m.simpleName, toValue));
                        } else {
                            sb.append(String.format("//          %s %s -->", m.type, m.simpleName));
                        }

                        sb.append("\n");
                    }
                    addSchema = true;
                }

            }
            if (inRow) {
                if (!addRow) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);
                        if (!m.isConvertToJsonStr()) {
                            sb.append(String.format("        if(doc.containsKey(\"%s\")){ m.%s(doc.get%s(\"%s\"));}", m.simpleName, m.getSetMethodName(), m.getParquetType(), m.simpleName));
                        } else {
                            sb.append(String.format("//          %s %s -->", m.type, m.simpleName));
                        }

                        sb.append("\n");
                    }
                    addRow = true;
                }

            }
            if (!inSchema && !inRow) {
                sb.append(line).append("\n");
            }
            if (StringUtils.contains(line, "/*--start_schema*/")) {
                inSchema = true;
            }
            if (StringUtils.contains(line, "/*--start_row*/")) {
                inRow = true;
            }


        }
        FileUtils.write(outFile, sb.toString(), "UTF-8");
        System.out.println(sb);
    }

    public static void generateHbaseConvert(File outFile, List<FieldInfo> fieldInfos) throws IOException {
        List<String> lines = FileUtils.readLines(outFile, "utf-8");
        StringBuilder sb = new StringBuilder();
        boolean inSchema = false;
        boolean addSchema = false;
        boolean inRow = false;
        boolean addRow = false;
        for (String line : lines) {
            if (StringUtils.contains(line, "/*--end_schema*/")) {
                inSchema = false;

            }
            if (StringUtils.contains(line, "/*--end_row*/")) {
                inRow = false;

            }
            if (inSchema) {
                if (!addSchema) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);
                        String toValue;
                        if (!m.isConvertToJsonStr()) {
                            toValue = String.format("m.%s()", m.getGetMethodName());
                            sb.append(String.format("        if(m.%s()!=null){put.addColumn(d, Bytes.toBytes(\"%s\"), Bytes.toBytes(%s));}", m.getGetMethodName(), m.simpleName, toValue));
                        } else {
                            sb.append(String.format("//          %s %s -->", m.type, m.simpleName));
                        }

                        sb.append("\n");
                    }
                    addSchema = true;
                }

            }
            if (inRow) {
                if (!addRow) {
                    System.out.println("未实现");
                    addRow = true;
                }

            }
            if (!inSchema && !inRow) {
                sb.append(line).append("\n");
            }
            if (StringUtils.contains(line, "/*--start_schema*/")) {
                inSchema = true;
            }
            if (StringUtils.contains(line, "/*--start_row*/")) {
                inRow = true;
            }


        }
        FileUtils.write(outFile, sb.toString(), "UTF-8");
        System.out.println(sb);
    }

    public static void generateFixTripCode(File outFile, List<FieldInfo> fieldInfos) throws IOException {
        Map<String, List<FieldInfo>> map = new LinkedHashMap<>();
        for (int i = 0; i < fieldInfos.size(); i++) {
            FieldInfo m = fieldInfos.get(i);
            String group = m.group;
            if ("none".equalsIgnoreCase(group)) {
                group = m.name;
            }
            String classify = m.classify;
            if ("fuel".equalsIgnoreCase(classify) || "mileage".equalsIgnoreCase(classify) || "duration".equalsIgnoreCase(classify)) {

                String key = group + "_" + classify;
                List<FieldInfo> list = map.get(key);
                if (list == null) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                list.add(m);
            }
        }
        List<String> lines = FileUtils.readLines(outFile, "utf-8");
        StringBuilder sb = new StringBuilder();
        boolean inSchema = false;
        boolean addSchema = false;
        boolean inRow = false;
        boolean addRow = false;
        for (String line : lines) {
            if (StringUtils.contains(line, "/*--end_schema*/")) {
                inSchema = false;

            }
            if (StringUtils.contains(line, "/*--end_row*/")) {
                inRow = false;

            }
            if (inSchema) {
                if (!addSchema) {
                    for (Map.Entry<String, List<FieldInfo>> entry : map.entrySet()) {
                        String[] ss = entry.getKey().split("_");
                        String group = ss[0];
                        String classify = ss[1];
                        List<FieldInfo> list = entry.getValue();
                        FieldInfo m0 = list.get(0);
                        String t0 = "total" + StringUtils.capitalize(m0.classify) + "0";
                        String t1 = "total" + StringUtils.capitalize(m0.classify);
                        if (list.size() == 1) {
                            sb.append(String.format("        //%s", m0.comment));
                            sb.append("\n");
                            sb.append(String.format("        m.%s(getCorrectResult(%s,%s,m.%s()));", m0.getSetMethodName(), t0, t1, m0.getGetMethodName()));
                            sb.append("\n");
                        } else {
                            sb.append(String.format("        //%s %s", group, classify)).append("\n");
                            sb.append(String.format("        ints = getCorrectResult(%s, new Integer[]{", t1)).append("\n");
                            for (int j = 0; j < list.size(); j++) {
                                FieldInfo m = list.get(j);
                                sb.append(String.format("                m.%s()", m.getGetMethodName()));
                                if (j != list.size() - 1) {
                                    sb.append(",");
                                }
                                sb.append("\n");
                            }
                            sb.append("        });").append("\n");
                            for (int j = 0; j < list.size(); j++) {
                                FieldInfo m = list.get(j);
                                sb.append(String.format("        m.%s(ints[" + j + "]);", m.getSetMethodName()));
                                sb.append("\n");
                            }
                        }
                    }

                    addSchema = true;
                }

            }
            if (inRow) {
                if (!addRow) {
                    addRow = true;
                }

            }
            if (!inSchema && !inRow) {
                sb.append(line).append("\n");
            }
            if (StringUtils.contains(line, "/*--start_schema*/")) {
                inSchema = true;
            }
            if (StringUtils.contains(line, "/*--start_row*/")) {
                inRow = true;
            }


        }
        FileUtils.write(outFile, sb.toString(), "UTF-8");
        System.out.println(sb);
    }

    public static void generateHiveTableSql(File outHiveSqlFile, String hiveTableName, String hiveTableComment, List<FieldInfo> fieldInfos) throws IOException {
        StringBuilder sb = new StringBuilder();

        sb.append("create external table if not exists ${hiveconf:hive_db}.").append(hiveTableName).append("(").append("\n");
        int maxFieldLength = fieldInfos.stream().map(t -> t.getHiveName().length()).max(Integer::compareTo).get();
        int maxTypeLength = fieldInfos.stream().map(t -> t.getHiveType().length()).max(Integer::compareTo).get();

        for (int i = 0; i < fieldInfos.size(); i++) {
            FieldInfo m = fieldInfos.get(i);
            sb.append(String.format("   %s" + space(4 + maxFieldLength - m.getHiveName().length()) + "%s" + space(2 + maxTypeLength - m.getHiveType().length()) + " comment '%s'", m.getHiveName(), m.getHiveType(), m.comment));
            if (i != fieldInfos.size() - 1) {
                sb.append(",");
            }
            sb.append("\n");
        }
        sb.append(")").append("\n");
        sb.append("comment ").append("'").append(hiveTableComment).append("'").append("\n");
        sb.append("partitioned by (day string comment '分区时间')").append("\n");
        sb.append("stored as Parquet TBLPROPERTIES('parquet.compression'='SNAPPY');").append("\n");
        System.out.println(sb.toString());
        FileUtils.write(outHiveSqlFile, sb.toString(), "UTF-8");
    }

    public static void generatePojoFields(File outPojoFile, List<FieldInfo> fieldInfos) throws IOException {
        List<String> lines = FileUtils.readLines(outPojoFile, "utf-8");
        StringBuilder sb = new StringBuilder();
        boolean inRow = false;
        boolean addRow = false;
        for (String line : lines) {
            if (StringUtils.contains(line, "/*--end_fields*/")) {
                inRow = false;

            }

            if (inRow) {
                if (!addRow) {
                    for (int i = 0; i < fieldInfos.size(); i++) {
                        FieldInfo m = fieldInfos.get(i);
                        String name = m.name;
                        String comment = m.comment;
//                        String name = m.simpleName;
//                        String comment=m.name+"  "+m.comment;
                        sb.append("     /**\n" +
                                "     * " + comment + "\n" +
                                "     **/\n");
                        sb.append(String.format("    private %s %s;", m.getPojoFieldType(), name));
                        sb.append("\n");
                        sb.append("\n");
                    }
                    addRow = true;
                }

            }
            if (!inRow) {
                sb.append(line).append("\n");
            }

            if (StringUtils.contains(line, "/*--start_fields*/")) {
                inRow = true;
            }


        }
        FileUtils.write(outPojoFile, sb.toString(), "UTF-8");
    }

    public static String space(int n) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append(" ");
        }
        return sb.toString();
    }


    public static List<FieldInfo> getFieldInfos(File pojoFilePath) throws Exception {
        List<FieldInfo> m1s = new ArrayList<>();
        List<String> lines = FileUtils.readLines(pojoFilePath, Charset.forName("UTF-8")).stream().map(t -> t.trim()).filter(t -> !org.apache.commons.lang3.StringUtils.startsWith(t, "#") && t.length() > 0).collect(Collectors.toList());
        for (String l : lines) {
            String[] ss = l.split(",");
            if (ss.length < 6) {
                System.out.println(l);
            }
            FieldInfo m = new FieldInfo();
            m.simpleName = ss[0];
            m.name = ss[1];
            m.type = ss[2].replace("@", ",");
            m.comment = ss[3];
            m.classify = ss[4];
            m.group = ss[5];
            m.supportflag = ss[6];
            m1s.add(m);
        }

        return m1s;
    }
}
